# 以真值表的形式对布尔函数进行一些相关计算

#pragma once

#include <iostream>
#include <cmath>

# 所有的相关函数都需要一个全局 var，控制变元。


# n 元内积		cdot(var, x, y))
# 另一种内积		int inner_dot(int x, int y))

# Walsh			int Walsh(const int F[], const int w))
# 自相关			int  Autocorrelation(const int F[], const int a))
# Δ_f				int Delat_f(const int* F))
# δ_f				int delat_f(const int* F))
# 平衡			bool Balanced(const int F[]))
# 最大Walsh绝对值	int Max_Abs_Walsh(const int F[]))
# 非线性度		int nonlinear(int* F))
# 是否Bent			bool if_bent(int* f))

# 汉明距离		int hb(int* bf1, int* bf2))
# 真值表等价		bool ifequal(int* bf1, int* bf2))

# 打印信息		void print_bf(int* f)




# n 元布尔向量内积
# 输入 n, x, y
# x, y 为 “真值表”
def cdot(n, x, y):
    res = 0
    for i in range(n):
        res = res ^ (x[i] * y[i])
        pass
    return res

# Walsh 函数中调用的 内积 inner_dot 函数
# 使用十进制数x，y来表示他们的二进制向量
def inner_dot(x, y):
    tmp = x & y    # 各位做乘法，“&”是按位与运算
    num = 0
    while tmp:
        tmp &= (tmp - 1)
        num += 1

    num &= 1
    return num

# Walsh函数，求F的walsh系数值，需要输入一个布尔函数F，以及点w
def Walsh(var, F, w):
    sum = 0
    for x in range(1 << var):
        num = inner_dot(x, w)
        num ^= F[x] # F[x]+x*w的奇偶性
        sum += num  # 1的个数
        pass
    return (1 << var) - 2 * sum # 1的个数减去0的个数就是walsh系数值


# 自相关函数
def  Autocorrelation(var, F, a):
    sum = 0
    for x in range(1 << var):
        if ((F[x ^ a] ^ F[x]) == 0):
            sum += 1		
        else:
            sum -= 1		

    return sum


# Δ_f
# 遍历自相关，绝对值的最大值，越小越好
def delat_f(var, F):
    D = 0
    d = 0
    for i in range(1, 1<<var):	
        p = Autocorrelation(var, F, i)
        if d < p:
            d = p
        p = abs(p)
        if D < p:
            D = p
            
    print("自相关绝对值的最大值：", D)
    print("最大自相关值：", d)



# # δ_f
# # 遍历自相关，最大值，越大越好
# def delat_f(var, F): 
#     d = 0
#     for i in range(1, 1<<var):	
#         p = Autocorrelation(var, F, i)
#         if d < p:
#             d = p		

#     return d


# 是否平衡
def Balanced(var, F):

    return not(Walsh(var, F, 0))


# walsh谱绝对值最大值
def Max_Abs_Walsh(var, F):
    temp = 0
    max_a_w = 0
    for i in range(1 << var):
        temp = abs(Walsh(var, F, i))
        if (temp > max_a_w):
            max_a_w = temp

    return max_a_w


# 计算布尔函数的非线性度。
def nonlinear(var, F):
    nonlinear = 0
    nonlinear = (1 << (var - 1)) - Max_Abs_Walsh(var, F) / 2
    return int(nonlinear)


# 是否 bent
def if_bent(var, f):
    if (var % 2 != 0):
        return False
    else:
        all_equal = (1 << int(var / 2))
        for i in range(1 << var):
            if (abs(Walsh(var, f, i)) != all_equal):
                return False
        
    return True


# 计算两个布尔函数的汉明距离
def hb(var, bf1, bf2):
    hamb = 0
    for i in range(1, var):
        if (bf1[i] != bf2[i]):
            hamb += 1
    return hamb


# 判断两个布尔函数是不是一样了……
def ifequal(bf1, bf2):
    return bf1 == bf2



# 根据定义来判断 s 是否为 f 的线性结构
def if_ls_def(var, f, s):
    result = -1
    if f[s] == 0:
        result =1
    elif f[s] == 1:
        result =0
    else:
        return False
    for i in range(1, 1<<var):
        # python 没有 case 我是没想到的
        #print(i, f[i], f[i^s])
        if f[i]^f[i^s]^result:
            pass
        else:
            return False
    return True


# 判断f是否有非零线性结构并输出这些非零线性结构
def print_liner_structure(var, f):
    res = False
    for s in range(1, 1<<var):
        if if_ls_def(var, f, s):
            if not res:
                res = True
            print(bin(s)[2:])
    return res


# 打印相关信息
def print_bf(var, f): 
    n_0 = 0
    n_1 = 0
    print("\n布尔函数的真值表为: ")
    for i in range(1, 1<<var):
        if (f[i]):
            n_1 += 1
        else:
            n_0 += 1
    
    print(f)
    print("\n-----------------------------\n")
    print("0：", n_0)
    print("1：", n_1)
    print("-----------------------------\n")
    print("非线性度：", nonlinear(var, f))
    delat_f(var, f)
    print("是否bent：", "是" if(if_bent(var, f)) else "否")
    print("*************\n有关非零线性结构：")
    print("以上为函数的非零线性结构" if print_liner_structure(var, f) else "该函数无非零线性结构")



if __name__ == '__main__':
    print("有关布尔函数的一些东西")
